﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BibMan.util {
    [Serializable]
    public class IndexedSet<T> : ISet<T>, IList<T>, ICollection<T>, IEnumerable<T> {

        private List<T> list;
        private HashSet<T> set;

        public IndexedSet() {
            this.list = new List<T>();
            this.set = new HashSet<T>();
        }
        public IndexedSet(int capacity) {
            this.list = new List<T>(capacity);
        }
        public IndexedSet(IEnumerable<T> collection) {
            this.list = new List<T>(collection);
            this.set = new HashSet<T>(collection);
        }
        public IndexedSet(EqualityComparer<T> comparer) {
            this.set = new HashSet<T>(comparer);
        }
        public IndexedSet(IEnumerable<T> collection, EqualityComparer<T> comparer) {
            this.list = new List<T>(collection);
            this.set = new HashSet<T>(collection, comparer);
        }
        public IndexedSet(int capacity, EqualityComparer<T> comparer) {
            this.list = new List<T>(capacity);
            this.set = new HashSet<T>(comparer);
        }

        public bool Add(T item) {
            if (set.Add(item)) {
                list.Add(item);
                return true;
            }
            return false;
        }

        public void ExceptWith(IEnumerable<T> other) {
            set.ExceptWith(other);
        }

        public void IntersectWith(IEnumerable<T> other) {
            set.IntersectWith(other);
        }

        public bool IsProperSubsetOf(IEnumerable<T> other) {
            return set.IsProperSubsetOf(other);
        }

        public bool IsProperSupersetOf(IEnumerable<T> other) {
            return set.IsProperSupersetOf(other);
        }

        public bool IsSubsetOf(IEnumerable<T> other) {
            return set.IsSubsetOf(other);
        }

        public bool IsSupersetOf(IEnumerable<T> other) {
            return set.IsSupersetOf(other);
        }

        public bool Overlaps(IEnumerable<T> other) {
            return set.Overlaps(other);
        }

        public bool SetEquals(IEnumerable<T> other) {
            return set.SetEquals(other);
        }

        public void SymmetricExceptWith(IEnumerable<T> other) {
            set.SymmetricExceptWith(other);
        }

        public void UnionWith(IEnumerable<T> other) {
            set.UnionWith(other);
        }

        void ICollection<T>.Add(T item) {
            if (set.Add(item)) {
                list.Add(item);
            }
        }

        public void Clear() {
            list.Clear();
            set.Clear();
        }

        public bool Contains(T item) {
            return set.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex) {
            list.CopyTo(array, arrayIndex);
        }

        public int Count {
            get { return list.Count; }
        }

        public bool IsReadOnly {
            get { return false; }
        }

        public bool Remove(T item) {
            if (set.Remove(item)) {
                return list.Remove(item);
            }
            return false;
        }

        public IEnumerator<T> GetEnumerator() {
            return list.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            return list.GetEnumerator();
        }

        public int IndexOf(T item) {
            return list.IndexOf(item);
        }

        void IList<T>.Insert(int index, T item) {
            if (set.Add(item)) {
                list.Insert(index, item);
            }
        }

        public bool Insert(int index, T item) {
            if (set.Add(item)) {
                list.Insert(index, item);
                return true;
            }
            return false;
        }

        void IList<T>.RemoveAt(int index) {
            if (set.Remove(list[index])) {
                list.RemoveAt(index);
            }
        }

        public bool RemoveAt(int index) {
            if (set.Remove(list[index])) {
                list.RemoveAt(index);
                return true;
            }
            return false;
        }

        public T this[int index] {
            get {
                return list[index];
            }
            set {
                list[index] = value;
            }
        }
    }
}